import re
from logging import getLogger

from QQLoginTool.QQtool import OAuthQQ
from django import http
from django.conf import settings
from django.contrib.auth import login
from django.http import JsonResponse, HttpResponseServerError, HttpResponseForbidden
from django.shortcuts import render, redirect

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from oauth.utils import check_access_token, generate_access_token
from users.models import User
from .models import OAuthQQUser


logger = getLogger('django')

class QQLoginView(View):
    """
    QQ登录
    """

    def get(self, request):
        """
        qq登录请求 /qq/login/?next=
        next: 发送请求的网页
        返回: 登录二维码网址
        """
        next = request.GET.get('next')  # 获取QQ登录页面网址

        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI,
                        state=next)

        login_url = oauth.get_qq_url()

        return JsonResponse({'code': 200, 'errmsg': 'OK', 'login_url': login_url})


class QQCallbackView(View):
    """
    QQ登录回调
    """

    def get(self, request):

        code = request.GET.get('code')

        if not code:
            return HttpResponseForbidden('缺少code')

        # 创建QQ登录工具
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI)

        # 通过工具向QQ官方发送code，获取许可，再发送许可获取用户 openid
        try:
            access_token = oauth.get_access_token(code)

            openid = oauth.get_open_id(access_token)
        except Exception as e:
            logger.error(e)
            return HttpResponseServerError('OAuth2.0认证失败')

        # QQ首次登录验证
        oauth_user = OAuthQQUser.objects.filter(openid=openid)

        if oauth_user:
            # 非首次登录
            oauth_user = oauth_user[0]
            # 保存登录在状态
            login(request, oauth_user.user)
            # 重定向到state:从哪来，QQ登录完之后回哪而去
            next = request.GET.get('state')
            response = redirect(next)
            # 将用户名写入到cookies中
            response.set_cookie('username', oauth_user.user.username,
                                max_age=3600 * 24 * 15)
            # 响应QQ登录结果
            return response
        else:
            # 首次登录
            access_token_openid = generate_access_token(openid)
            context = {'access_token_openid': access_token_openid}
            return render(request, 'oauth_callback.html', context)


    def post(self, request):
        """第三方首次登录绑定手机号"""

        # 接收参数
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        sms_code = request.POST.get('sms_code')
        access_token_openid = request.POST.get('access_token_openid')

        # 校验参数
        # 判断参数是否齐全
        if not all([mobile, password, sms_code]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号码')
        # 判断密码是否合格
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')
        # 判断短信验证码是否一致
        redis_conn = get_redis_connection('verify')
        redis_sms_code = redis_conn.get('sms_%s' % mobile)
        if redis_sms_code is None:
            return render(request, 'oauth_callback.html',
                          {'code_sms_error':'无效的短信验证码'})
        if sms_code != redis_sms_code.decode():
            return render(request, 'oauth_callback.html',
                          {'code_sms_error':'输入短信验证码有误'})
        # 判断openid是否有效：错误提示放在sms_code_errmsg位置
        openid = check_access_token(access_token_openid)
        if not openid:
            return render(request, 'oauth_callback.html', {'openid_errmsg': 'QQ登录已超时'})
            # 查询手机号
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 新手机号，新建用户
            user = User.objects.create_user(username=mobile,
                                            password=password,
                                            mobile=mobile)
        else:
            # 老用户，需要校验密码
            if not user.check_password(password):
                return render(request, 'oauth_callback.html',
                              {'account_errmsg': '账号或密码错误'})
        # 将新建用户、已存在用户绑定到openid
        # oauth_qq_user = OAuthQQUser(user=user, openid=openid)
        # oauth_qq_user.save()
        try:
            oauth_qq_user = OAuthQQUser.objects.create(user=user, openid=openid)
        except Exception as e:
            logger.error(e)
            return render(request, 'oauth_callback.html',
                          {'qq_login_errmsg': 'QQ绑定失败，请稍后重试'})

        # openid已绑定美多商城用户:oauth_user.user表示从QQ登陆模型类对象中找到对应的用户模型类对象
        login(request, oauth_qq_user.user)
        # 重定向到state:从哪来，QQ登录完之后回哪而去
        next = request.GET.get('state')
        response = redirect(next)
        # 将用户名写入到cookies中
        response.set_cookie('username', oauth_qq_user.user.username,max_age=3600 * 24 * 15)
        # 响应QQ登录结果
        return response

